package network

import (
	"bytes"
	"encoding/json"
	"fmt"
	zkdriver "github.com/samuel/go-zookeeper/zk"
	"go-tcpFramework-rudy/config"
	"go-tcpFramework-rudy/logger"
	"go-tcpFramework-rudy/util"
	"go-tcpFramework-rudy/zk"
	"golang.org/x/net/context"
	"golang.org/x/net/websocket"
	"log"

	"net"
	"net/http"
	"os"
	"time"
)

const TYPE_TCP_SERVER = 1

type Server struct {
	Address   string
	listener  *net.TCPListener
	servrType int32
	cMgr      ConnectionManager
	h HandleFunction
}

func badCall() {
	panic("bad end")
}

func ServerFactory(adress string) Server {
	ret :=  Server{Address:adress,listener:nil,servrType:1,cMgr:*GetConnMgr(),h:DefaultPackageHandler}
	return ret
}

func websocketHandler(ws *websocket.Conn) {
	defer logger.PanicHandler()

	var clicnn ConnectionContext
	clicnn.Type = "websocket"
	clicnn.Port = GetPort(ws.RemoteAddr().String())
	clicnn.IpAdress = GetIpAddr(ws.RemoteAddr().String())
	clicnn.Cnntime = time.Now().Unix()
	clicnn.wsCnn = ws
	e := GetConnMgr().AddConn(clicnn)
	if nil != e {
		logger.LogDebugError(e.Error())
	}

	logger.LogRealeaseInfo("accept conn", ws.RemoteAddr().String(), ws.LocalAddr().String())

	go HandleConnection(clicnn)
}

func (this *Server) SetIpAddress(Address string) {
	this.Address = Address
}
func (this *Server)SetHandler(h HandleFunction)  {
	this.h = h
}

func (this *Server) Run() error {
	defer logger.PanicHandler()

	e := zk.ConnectZooKeeper()
	if nil != e {
		logger.LogDebugError(e.Error())
	}

	go func() {
		for true {
			time.Sleep(time.Second * 10)
			e := SyncServerStatus()
			if nil != e {
				logger.LogDebugError(e.Error())
			}
		}
	}()
	if config.Configs().Type == "websocket" {
		for {
			http.Handle("/ws", websocket.Handler(websocketHandler))
			err := http.ListenAndServe(config.Configs().Ipadress, nil)
			if err != nil {
				log.Println(err.Error())
				return err
			}
		}
	} else {
		tcpAddr, err := net.ResolveTCPAddr("tcp4", this.Address)
		if nil != err {
			logger.LogDebugError(err.Error())
		}
		this.listener, err = net.ListenTCP("tcp4", tcpAddr)
		if nil != err {
			logger.LogDebugError(err.Error())
		}
		for {
			c,err := this.listener.AcceptTCP()
			if err != nil {
				if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
					fmt.Println("Stop accepting connections")
					return err
				}
			}
			ctxCnn := withTimeoutConnectContext(context.Background(), time.Second*200)
			ctxCnn.Type = "tcp"
			ctxCnn.Port = GetPort(c.RemoteAddr().String())
			ctxCnn.IpAdress = GetIpAddr(c.RemoteAddr().String())
			ctxCnn.Cnntime = time.Now().Unix()
			ctxCnn.Cnn = c

			file, _ := c.File()
			ctxCnn.fd = file.Fd()

			e := GetConnMgr().AddConn(ctxCnn)
			if nil != e {
				logger.LogRealeaseInfo(ctxCnn.fd)
				logger.LogDebugError(e.Error())
			}
			logger.LogRealeaseInfo("accept conn", c.RemoteAddr().String(), c.LocalAddr().String())
			if err != nil {
				logger.LogDebugError(err.Error())
				continue
			}
			go HandleConnection(ctxCnn)
		}
	}
}

func SyncServerStatus() error {
	var rs zk.ServerStatus
	acl := zkdriver.WorldACL(zkdriver.PermAll)

	defer logger.PanicHandler()
	rs.ServerID = config.Configs().ID
	rs.CnnCount = GetConnMgr().GetCount()
	bj, e := json.Marshal(rs)
	if e != nil {
		logger.LogDebugError([]interface{}{e.Error()})
		return e
	}
	//log.Println(Configs())
	ok, _, e := zk.ZkInstance().Exists("/logic/" + config.Configs().ID)
	if e != nil {
		logger.LogDebugError([]interface{}{e.Error()})
	}
	if !ok {
		ok1, _, err := zk.ZkInstance().Exists("/logic")
		if !ok1 {
			path, err := zk.ZkInstance().Create("/logic", bytes.NewBufferString(time.Now().String()).Bytes(), 0, acl)
			if nil != err {
				logger.LogDebugError([]interface{}{err.Error()})
			}
			logger.LogDebugError([]interface{}{path})
		}
		_, err = zk.ZkInstance().Create("/logic/"+config.Configs().ID, bj, zkdriver.FlagEphemeral, acl)
		if nil != err {
			logger.LogDebugError([]interface{}{err.Error()})
		}
		//logger.LogRealeaseInfo([]interface{}{})
		//log.Println(string(ret))
	} else {
		e := zk.ZkInstance().Delete("/logic/"+config.Configs().ID, -1)
		if e != nil {
			logger.LogDebugError([]interface{}{e.Error()})
		}
		_, err := zk.ZkInstance().Create("/logic/"+config.Configs().ID, bj, zkdriver.FlagEphemeral, acl)
		if nil != err {
			logger.LogDebugError([]interface{}{err.Error()})
		}
	}
	return nil
}

func (this *Server) StopListen() error {
	e := this.listener.SetDeadline(time.Now())
	if nil != e {
		logger.LogDebugError(e.Error())
		return e
	}
	return nil
}

func (this *Server) RestartGraceful() {
	e := os.Setenv(util.ENV_GRACEFUL_RESTART, "true")
	if nil != e {
		logger.LogDebugError(e.Error())
	}
	//todo stop listen socket
	e = this.StopListen()
	if nil != e {
		logger.LogDebugError(e.Error())
	}
	//todo wait for conection goroutine all stop

}
